// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { Palette } from "std-widgets.slint";
import { Api, BrushKind, ColorData, GradientStop, PropertyValue, PropertyValueKind, PreviewData } from "../../api.slint";
import { EditorSpaceSettings, EditorSizeSettings, EditorPalette } from "../../components/styling.slint";
import { WindowManager, ColorCodeType, BrushPropertyType, PickerData } from "../../windowglobal.slint";
import { ColorIndicator, GradientIndicator, FakeShadowText, PickerTextInput } from "brush-helpers.slint";
import { CustomLineEdit } from "./widget-helpers.slint";

component InlineColor {
    width: 100%;
    height: main.height;

    in-out property <color> current-color;
    out property <bool> has-focus: main.has-focus || percent.has-focus;

    callback indicator-clicked();
    callback set-color-binding(text: string);

    changed current-color => {
        ti-hex-color.text = Api.color-to-data(root.current-color).short-text.to-uppercase();
        pi.text = (root.current-color.to-hsv().alpha * 100.0).round();
    }

    main := CustomLineEdit {
        x: 0;
        width: parent.width - (percent.width + 10px);
        has-focus: ti-hex-color.has-focus;
        ci := ColorIndicator {
            x: (main.height - 15px) / 2;
            y: (parent.height - self.height) / 2;
            color: root.current-color;

            TouchArea {
                clicked => {
                    root.indicator-clicked();
                }
            }
        }

        Rectangle {
            x: ci.x + ci.width + 4px;
            width: 170px;
            height: 25px;

            FakeShadowText {
                x: 0;
                font-family: "Inter";
                font-size: 11px;
                text: "#";
            }

            ti-hex-color := PickerTextInput {
                x: 10px;
                text: Api.color-to-data(root.current-color).short-text.to-uppercase();
                letter-spacing: 0.8px;
                input-type: text;
                property <{hue: float, saturation: float, value: float, alpha: float}> hsv-color;
                function apply-text(text: string) {
                    if Api.string-is-color("#\{self.text}") {
                        hsv-color.hue = Api.string-to-color("#\{self.text}").to-hsv().hue;
                        hsv-color.saturation = Api.string-to-color("#\{self.text}").to-hsv().saturation;
                        hsv-color.value = Api.string-to-color("#\{self.text}").to-hsv().value;
                        hsv-color.alpha = root.current-color.to-hsv().alpha;
                        if self.text.character-count > 6 {
                            hsv-color.alpha = Api.string-to-color("#\{self.text}").to-hsv().alpha;
                        }
                        if hsv-color.alpha == 1 {
                            root.set-color-binding("#\{Api.color-to-data(hsv(hsv-color.hue, hsv-color.saturation, hsv-color.value, hsv-color.alpha)).short-text}");
                        } else {
                            root.set-color-binding(Api.color-to-data(hsv(hsv-color.hue, hsv-color.saturation, hsv-color.value, hsv-color.alpha)).text);
                        }
                    } else {
                        self.text = Api.color-to-data(root.current-color).short-text.to-uppercase();
                    }
                }
                accepted => {
                    apply-text(self.text);
                    self.clear-focus();
                }
                edited => {
                    if self.text.character-count > 8 {
                        self.text = Api.color-to-data(root.current-color).short-text.to-uppercase();
                    }
                }
                changed has-focus => {
                    if !self.has-focus {
                        apply-text(self.text);
                    }
                }
            }
        }
    }

    percent := CustomLineEdit {
        x: parent.width - self.width;
        width: 50px;
        has-focus: pi.has-focus;
        Rectangle {
            x: parent.width - self.width;
            width: 48px;
            height: parent.height;

            pi := PickerTextInput {
                x: -20px;
                text: (root.current-color.to-hsv().alpha * 100.0).round();
                horizontal-alignment: right;
                accepted => {
                    self.text = clamp(self.text.to-float(), 0, 100);
                    if self.text == "100" {
                        root.set-color-binding("#\{Api.color-to-data(hsv(root.current-color.to-hsv().hue, root.current-color.to-hsv().saturation, root.current-color.to-hsv().value, 1)).short-text}");
                    } else {
                        root.set-color-binding(Api.color-to-data(hsv(root.current-color.to-hsv().hue, root.current-color.to-hsv().saturation, root.current-color.to-hsv().value, self.text.to-float() / 100)).text);
                    }
                    self.clear-focus();
                }
                edited => {
                    if self.text.character-count > 3 {
                        self.text = clamp(self.text.to-float(), 0, 100);
                    }
                }
            }

            FakeShadowText {
                x: parent.width - self.width - 5px;
                font-family: "Inter";
                font-size: 11px;
                text: "%";
            }
        }
    }
}

component InlineGradient {
    width: 100%;
    height: main.height;

    in-out property <brush> current-brush;
    in-out property <BrushKind> current-brush-kind;

    callback indicator-clicked();

    main := CustomLineEdit {
        x: 0;
        width: parent.width;
        ci := GradientIndicator {
            x: (main.height - 15px) / 2;
            y: (parent.height - self.height) / 2;
            brush: root.current-brush;

            TouchArea {
                clicked => {
                    root.indicator-clicked();
                }
            }
        }

        Rectangle {
            x: 16px;
            width: parent.width - self.x;
            height: 25px;

            Text {
                x: 10px;
                text: root.current-brush-kind == BrushKind.linear ? "Linear Gradient" : root.current-brush-kind == BrushKind.radial ? "Radial Gradient" : "Conic Gradient";
                font-family: "Inter";
                font-size: 12px;
                color: EditorPalette.text-color;
            }
        }
    }
}

component UnsetColor {
    width: 100%;
    height: main.height;

    in-out property <BrushPropertyType> brush-property-type;

    callback indicator-clicked();

    main := CustomLineEdit {
        x: 0;
        width: parent.width;
        ci := Rectangle {
            x: (main.height - 15px) / 2;
            y: (parent.height - self.height) / 2;
            width: 15px;
            height: 15px;
            background: white;
            border-radius: self.width / 2;
            clip: true;

            Path {
                commands: "M 350 50 L 50 250";
                stroke: red;
                stroke-width: 1px;
            }

            Rectangle {
                border-width: 1px;
                border-color: Palette.border;
                border-radius: self.width / 2;
            }

            TouchArea {
                clicked => {
                    root.indicator-clicked();
                }
            }
        }

        Rectangle {
            x: 16px;
            width: parent.width - self.x;
            height: 25px;

            Text {
                x: 10px;
                text: root.brush-property-type == BrushPropertyType.color ? "color" : "brush";
                font-family: "Inter";
                font-size: 12px;
                color: EditorPalette.text-color;
            }
        }
    }
}

component ColorCode {
    width: 100%;
    height: main.height;

    in property <BrushKind> brush-kind;
    in property <brush> brush;
    in property text <=> t.text;

    callback clicked <=> ta.clicked;

    main := CustomLineEdit {
        x: 0;
        width: parent.width;

        if root.brush-kind == BrushKind.solid: ColorIndicator {
            x: (main.height - 15px) / 2;
            y: (parent.height - self.height) / 2;
            color: root.brush;
        }
        if root.brush-kind != BrushKind.solid: GradientIndicator {
            x: (main.height - 15px) / 2;
            y: (parent.height - self.height) / 2;
            brush: root.brush;
        }

        ta := TouchArea { }

        Rectangle {
            x: 16px;
            width: parent.width - self.x;
            height: 25px;

            t := Text {
                x: 10px;
                width: parent.width - self.x - EditorSizeSettings.standard-margin;
                overflow: elide;
                font-family: "Source Code Pro";
                font-size: 12px;
                color: EditorPalette.text-color;
            }
        }
    }
}

export component InlineBrushWidget inherits VerticalLayout {
    in property <bool> enabled;
    in property <string> property-name;
    in property <PropertyValue> property-value;
    in-out property <BrushPropertyType> brush-property-type;
    in property <string> property-container-id;
    in property <PreviewData> preview-data;
    property <ColorCodeType> color-code-type: PickerData.get-color-code-type(property-value);

    private property <color> current-color: Colors.transparent;

    callback test-color-binding(text: string) -> bool;
    callback set-color-binding(text: string);
    callback update-floating-editor();

    callback test-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> bool;
    callback set-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]);

    function set-brush-binding_impl(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) {
        self.update-display-string(kind == BrushKind.solid ? "Solid Color" : kind == BrushKind.linear ? "Linear Gradient" : "Radial Gradient");
        self.set-brush-binding(kind, angle, color, stops);
    }

    private property <brush> current-brush;
    private property <[GradientStop]> current-gradient-stops;
    private property <ColorData> current-color-data: Api.color-to-data(self.current-color);
    private property <BrushKind> current-brush-kind;
    private property <float> current-angle;
    private property <bool> has-focus;

    padding-left: 16px;

    callback update-display-string(value: string);

    function apply-value() {
        if self.property-value.kind == PropertyValueKind.brush {
            root.current-color = self.property-value.value-brush;
            root.current-color-data = Api.color-to-data(self.property-value.value-brush);
            root.current-brush = self.property-value.value-brush;
            root.current-brush-kind = self.property-value.brush-kind;
            root.current-gradient-stops = self.property-value.gradient-stops;
            root.current-angle = self.property-value.value-float;
        }
        if self.property-value.kind == PropertyValueKind.color {
            root.current-color = self.property-value.value-brush;
        }
    }

    function update-brush() {
        if self.property-value.kind == PropertyValueKind.brush {
            // Always use the angle we expect in the preview!
            root.current-brush = Api.create-brush(root.current-brush-kind, root.current-angle, root.current-brush, root.current-gradient-stops);
            root.test-brush-binding(root.current-brush-kind, root.current-angle, root.current-brush, root.current-gradient-stops);
        }
    }

    init => {
        apply-value();
        update-brush();
    }
    changed has-focus => {
        if !self.has-focus {
            apply-value();
        }
    }

    changed property-value => {
        if !self.has-focus {
            apply-value();
        }

        // Floating editors need to know the current property details. Call the update if something changes.
        if WindowManager.showing-color-picker && WindowManager.current-property-information.name == root.property-name {
            self.update-floating-editor();
        }
    }

    if property-value.code == "": UnsetColor {
        brush-property-type <=> root.brush-property-type;

        indicator-clicked() => {
            root.update-floating-editor();
        }
    }

    if property-value.brush-kind == BrushKind.solid && property-value.code != "" && root.color-code-type == ColorCodeType.other: InlineColor {
        current-color <=> root.current-color;

        changed has-focus => {
            root.has-focus = self.has-focus;
        }

        indicator-clicked() => {
            root.update-floating-editor();
        }
        set-color-binding(text) => {
            root.set-color-binding(text);
        }
    }

    if (property-value.brush-kind == BrushKind.linear || property-value.brush-kind == BrushKind.radial || property-value.brush-kind == BrushKind.conic) && property-value.code != "" && root.color-code-type == ColorCodeType.other: InlineGradient {
        current-brush <=> root.current-brush;
        current-brush-kind <=> root.current-brush-kind;

        indicator-clicked() => {
            root.update-floating-editor();
        }
    }

    if root.color-code-type != ColorCodeType.other: ColorCode {
        text: root.property-value.code;
        brush-kind <=> root.current-brush-kind;
        brush <=> root.current-brush;
        clicked => {
            root.update-floating-editor();
        }
    }
}
